﻿using System;
using System.Collections.Generic;
using System.Text;

namespace dotHTML.HTML {
    /// <summary>
    /// Represents an input control.
    /// </summary>
    [Serializable]
    [Standalone]
    public class Input : Element {
        /// <summary>
        /// Represents the different possible input types.
        /// </summary>
        public enum InputType {
            /// <summary>
            /// Represents a button.
            /// </summary>
            Button,
            /// <summary>
            /// Represents a checkbox.
            /// </summary>
            Checkbox,
            /// <summary>
            /// Represents a color chooser.
            /// </summary>
            Color,
            /// <summary>
            /// Represents a date chooser.
            /// </summary>
            Date,
            /// <summary>
            /// Represents a date and time chooser.
            /// </summary>
            DateTime,
            /// <summary>
            /// Represents a field in which an e-mail address can be entered.
            /// </summary>
            EMail,
            /// <summary>
            /// Represents a field in which a file can be chosen.
            /// </summary>
            File,
            /// <summary>
            /// A control that is not displayed, but whose value is submitted 
            /// to the server.
            /// </summary>
            Hidden,
            /// <summary>
            /// A graphical submit button.
            /// </summary>
            Image,
            /// <summary>
            /// Represents a field in which a month and year can be
            /// specified.
            /// </summary>
            Month,
            /// <summary>
            /// Represents a field in which a floating-point number can be
            /// entered.
            /// </summary>
            Number,
            /// <summary>
            /// Represents a field in which a password can be entered.
            /// </summary>
            Password,
            /// <summary>
            /// Represents a radio button.
            /// </summary>
            Radio,
            /// <summary>
            /// Represents a number whose exact value is not important.
            /// </summary>
            Range,
            /// <summary>
            /// A control that resets all other controls.
            /// </summary>
            Reset,
            /// <summary>
            /// A control that submits the form.
            /// </summary>
            Submit,
            /// <summary>
            /// Represents a telephone number.
            /// </summary>
            Tel,
            /// <summary>
            /// Represents a single line of text.
            /// </summary>
            Text,
            /// <summary>
            /// Represents a time value.
            /// </summary>
            Time,
            /// <summary>
            /// Represents a URL.
            /// </summary>
            Url,
            /// <summary>
            /// Represents a week-year number.
            /// </summary>
            Week
        }

        private InputType? _type;
        private ICollection<string> _accept;
        private bool? _autocomplete;
        private bool _autofocus;
        private bool _checked;
        private bool _disabled;
        private Form _form;
        private string _formaction;
        private string _formenctype;
        private FormMethodChoices? _formmethod;
        private bool _formnovalidate;
        private string _formtarget;
        private int? _height;
        private DataList _list;
        private int? _max;
        private int? _maxlength;
        private int? _min;
        private bool _multiple;
        private string _name;
        private string _pattern;
        private string _placeholder;
        private bool _readonly;
        private bool _required;
        private string _selectionDirection;
        private int? _size;
        private string _src;
        private float? _step;
        private Map _usemap;
        private string _value;

        /// <summary>
        /// Constructs a new instance of an Input element.
        /// </summary>
        public Input() {
            _accept = new LinkedList<string>();
        }

        /// <summary>
        /// Constructs a new Input element of the given type.
        /// </summary>
        /// <param name="type">The type of input field to construct.</param>
        public Input(InputType type)
            : this() {
            _type = type;
        }

        /// <summary>
        /// Determines the MIME types that the server supports.
        /// </summary>
        public ICollection<string> Accept {
            get { return _accept; }
        }

        /// <summary>
        /// Determines whether or not to use autocomplete functionality on this
        /// field.
        /// </summary>
        public bool? AutoComplete {
            get { return _autocomplete; }
            set { _autocomplete = value; }
        }

        /// <summary>
        /// Determines whether or not this control should have input focus when
        /// the page is loaded.
        /// </summary>
        public bool AutoFocus {
            get { return _autofocus; }
            set { _autofocus = value; }
        }

        /// <summary>
        /// Determines whether or not this control is selected by default.
        /// </summary>
        public bool Checked {
            get { return _checked; }
            set { _checked = value; }
        }

        /// <summary>
        /// Determines whether or not this control is disabled by default.
        /// </summary>
        public bool Disabled {
            get { return _disabled; }
            set { _disabled = value; }
        }

        /// <summary>
        /// Determines the ID of the parent form that this field belongs to.
        /// </summary>
        public Form Form {
            get { return _form; }
            set { _form = value; }
        }

        /// <summary>
        /// Determines the URL that the parent form will be submitted to.
        /// </summary>
        public string FormAction {
            get { return _formaction; }
            set { _formaction = value; }
        }

        /// <summary>
        /// Determines the encoding type for the submitted form data.
        /// </summary>
        public string FormEncType {
            get { return _formenctype; }
            set { _formenctype = value; }
        }

        /// <summary>
        /// Determines how to send the content in the parent form.
        /// </summary>
        public FormMethodChoices? FormMethod {
            get { return _formmethod; }
            set { _formmethod = value; }
        }

        /// <summary>
        /// Determines whether or not to validate the form before sending it.
        /// </summary>
        public bool FormNoValidate {
            get { return _formnovalidate; }
            set { _formnovalidate = value; }
        }

        /// <summary>
        /// Determines the location where the form submission result will be
        /// loaded.
        /// </summary>
        public string FormTarget {
            get { return _formtarget; }
            set { _formtarget = value; }
        }

        /// <summary>
        /// Defines the height of the image displayed for a button.
        /// </summary>
        public int? Height {
            get { return _height; }
            set { _height = value; }
        }

        /// <summary>
        /// Determines the datalist that this control is bound to.
        /// </summary>
        public DataList List {
            get { return _list; }
            set { _list = value; }
        }

        /// <summary>
        /// Determines the maximum value for this control.
        /// </summary>
        public int? Max {
            get { return _max; }
            set { _max = value; }
        }

        /// <summary>
        /// Determines the maximum number of characters that can be entered.
        /// </summary>
        public int? MaxLength {
            get { return _maxlength; }
            set { _maxlength = value; }
        }

        /// <summary>
        /// The minimum value for this control.
        /// </summary>
        public int? Min {
            get { return _min; }
            set { _min = value; }
        }

        /// <summary>
        /// Determines whether or not the user can enter multiple values.
        /// </summary>
        public bool Multiple {
            get { return _multiple; }
            set { _multiple = value; }
        }

        /// <summary>
        /// Determines the name of the form.
        /// </summary>
        public string Name {
            get { return _name; }
            set { _name = value; }
        }

        /// <summary>
        /// Determines the Regex pattern used to validate the control.
        /// </summary>
        public string Pattern {
            get { return _pattern; }
            set { _pattern = value; }
        }

        /// <summary>
        /// A hint to the user of what can be entered in the control.
        /// </summary>
        public string PlaceHolder {
            get { return _placeholder; }
            set { _placeholder = value; }
        }

        /// <summary>
        /// Determines whether or not this control is read-only.
        /// </summary>
        public bool ReadOnly {
            get { return _readonly; }
            set { _readonly = value; }
        }

        /// <summary>
        /// Determines whether or not input to this control is required for the
        /// form to validate.
        /// </summary>
        public bool Required {
            get { return _required; }
            set { _required = value; }
        }

        /// <summary>
        /// Determines the direction in which items were selected.
        /// </summary>
        public string SelectionDirection {
            get { return _selectionDirection; }
            set { _selectionDirection = value; }
        }

        /// <summary>
        /// Determines the initial size in pixels or length (whichever is
        /// appropriate) of this control.
        /// </summary>
        public int? Size {
            get { return _size; }
            set { _size = value; }
        }

        /// <summary>
        /// Determines the URL of an image to load for this control.
        /// </summary>
        public string Src {
            get { return _src; }
            set { _src = value; }
        }

        /// <summary>
        /// Determines the step size of this control.
        /// </summary>
        /// <remarks>Set to Float.NaN to have this output as "any".</remarks>
        public float? Step {
            get { return _step; }
            set { _step = value; }
        }

        /// <summary>
        /// Determines the type of this control.
        /// </summary>
        public InputType? Type {
            get { return _type; }
            set { _type = value; }
        }

        /// <summary>
        /// Determines the map to use with this control.
        /// </summary>
        [Obsolete("Deprecated in HTML4.")]
        public Map UseMap {
            get { return _usemap; }
            set { _usemap = value; }
        }

        /// <summary>
        /// Determines the initial value of this control.
        /// </summary>
        public string Value {
            get { return _value; }
            set { _value = value; }
        }

        /// <summary>
        /// Gets a formatted string of all local attributes of this element
        /// (not including the base attributes).
        /// </summary>
        /// <param name="sb">The StringBuilder to write this element's
        /// attribute data to.</param>
        protected override void WriteLocalAttributes(StringBuilder sb) {
            AttributeWriter.Write(sb, _accept, "accept", ',');
            if (_autocomplete != null) {
                AttributeWriter.Write(sb, _autocomplete.Value ? "on" : "off",
                    "autocomplete");
            }
            AttributeWriter.Write(sb, _autofocus, "autofocus");
            AttributeWriter.Write(sb, _checked, "checked");
            AttributeWriter.Write(sb, _disabled, "disabled");
            if (_form != null) {
                AttributeWriter.Write(sb, _form.ID, "form");
            }
            AttributeWriter.Write(sb, _formaction, "formaction");
            AttributeWriter.Write(sb, _formenctype, "formenctype");
            AttributeWriter.Write(sb, _formmethod, "formmethod", true);
            AttributeWriter.Write(sb, _formnovalidate, "formnovalidate");
            AttributeWriter.Write(sb, _formtarget, "formtarget");
            AttributeWriter.Write(sb, _height, "height");
            if (_list != null) {
                AttributeWriter.Write(sb, _list.ID, "list");
            }
            AttributeWriter.Write(sb, _max, "max");
            AttributeWriter.Write(sb, _maxlength, "maxlength");
            AttributeWriter.Write(sb, _min, "min");
            AttributeWriter.Write(sb, _multiple, "multiple");
            AttributeWriter.Write(sb, _name, "name");
            AttributeWriter.Write(sb, _pattern, "pattern");
            AttributeWriter.Write(sb, _placeholder, "placeholder");
            AttributeWriter.Write(sb, _readonly, "readonly");
            AttributeWriter.Write(sb, _required, "required");
            AttributeWriter.Write(sb, _selectionDirection, "selectiondirection");
            AttributeWriter.Write(sb, _size, "size");
            AttributeWriter.Write(sb, _src, "src");
            if (_step != null) {
                AttributeWriter.Write(sb, float.IsNaN(_step.Value) ? "any" : 
                    _step.Value.ToString(), "step");
            }
            AttributeWriter.Write(sb, _type, "type", true);
            if (_usemap != null) {
                AttributeWriter.Write(sb, _usemap.ID, "usemap");
            }
            AttributeWriter.Write(sb, _value, "value");
        }
    }
}
